package com.exploadingelephants.engine;

import android.graphics.Canvas;
import android.util.Log;

import com.exploadingelephants.util.Settings;
import com.exploadingelephants.views.PlaygroundView;

/**
 * Main Game Loop. Updates views, checks collisions, cleans up..
 */
public class PlayLoopThread extends Thread {
    /** Main playground */
    private final PlaygroundActivity playgroundActivity;

    /** Main playground View */
    private final PlaygroundView playgroundView;

    /** Indicator to stop, and start the thread */
    private boolean running = false;

    /** We can pause the game */
    private boolean paused = false;

    /**
     * @param view
     */
    public PlayLoopThread(PlaygroundActivity playgroundActivity,
	    PlaygroundView playgroundView) {
	this.playgroundActivity = playgroundActivity;
	this.playgroundView = playgroundView;
    }

    /**
     * Starts the main game loop
     */
    public void startLoop() {
	this.running = true;
    }

    /**
     * Stops the main game loop
     */
    public void stopLoop() {
	this.running = false;
    }

    /**
     * Pause game
     */
    public void pauseGame() {
	this.paused = true;
    }

    /**
     * Resume game
     */
    public void resumeGame() {
	this.paused = false;
    }

    @Override
    /**
     * Main game loop ;)
     */
    public void run() {

	long startTime;
	long sleepTime;

	while (keepRunning()) {
	    Canvas c = null;
	    startTime = System.currentTimeMillis();
	    if (!isPaused()) {
		try {
		    c = playgroundView.getHolder().lockCanvas();

		    synchronized (playgroundView.getHolder()) {
			updateSprites(c);
			checkCollisions();
			cleanupSprites();
		    }

		} finally {
		    if (c != null) {
			playgroundView.getHolder().unlockCanvasAndPost(c);
		    }
		}
	    }
	    // max calculation time to given to calculate one frame
	    long timeToSpentPerFrame = (1000 / Settings.FRAMES_PER_SECOND);
	    sleepTime = timeToSpentPerFrame
		    - (System.currentTimeMillis() - startTime);

	    try {
		if (sleepTime <= 0) {
		    sleepTime = Settings.PLAYLOOP_MIN_SLEEPTIME;
		}
		Log.d("PlayLoopThread", "Sleeptime: " + sleepTime + "ms");
		sleep(sleepTime);
	    } catch (Exception e) {
	    }
	}
	while (keepRunning())
	    ;

	if (playgroundActivity.isGameFinished()) {
	    playgroundActivity.onGameFinished();
	    Canvas c = playgroundView.getHolder().lockCanvas();
	    updateSprites(c);
	    playgroundView.getHolder().unlockCanvasAndPost(c);
	}
    }

    private boolean isPaused() {
	return this.paused;
    }

    /**
     * Should our main loop stop for good or keep running?
     */
    private boolean keepRunning() {
	return this.running && !playgroundActivity.isGameFinished();
    }

    /**
     * Update Elements
     */
    private void updateSprites(Canvas c) {
	playgroundView.updateBackground(c);
	playgroundActivity.updateSprites(c);
    }

    /**
     * Handle collisions
     */
    private void checkCollisions() {
	playgroundActivity.checkCollisions();
    }

    /**
     * Clean up the mess
     */
    private void cleanupSprites() {
	playgroundActivity.cleanupSprites();
    }
}